package com.asialjim.wechat.apiservice.executor;

import com.asialjim.wechat.apiservice.Api;
import com.asialjim.wechat.apiservice.ApiRequest;
import com.sun.xml.internal.ws.client.RequestContext;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.ContentType;
import org.apache.http.util.Args;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Map;
import java.util.Objects;

/**
 * <h1><em>ASIAL JIM JAVA DOC</em></h1><hr/>
 * <h2>CLASS DESCRIPTION <i>[ NAME: BaseApiExecutor ]</i></h2><strong>
 * <p> we-chat api executor
 * </strong><p><p><em>Copyright &copy; Asial Jim Co., LTD</em><hr/>
 *
 * @author Asial Jim &nbsp;&nbsp; <span>Email:<a href="mailto:asialjim@hotmail.com">asialjim@hotmail.com</a> &nbsp;&nbsp; <a href="asialjim@qq.com">asialjim@qq.com</a></span>
 * @version 1.0.0
 * @since 2021/3/1   &nbsp;&nbsp; JDK 8
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public abstract class BaseApiExecutor implements ApiExecutor {
    protected HttpHost httpProxy;
    protected String domain;
    protected String tempFilePath;

    protected static final Logger log = LoggerFactory.getLogger(BaseApiExecutor.class);

    @Override
    public <T> T execute(Api api, ApiRequest.RequestUrlParam urlParam, ApiRequest.RequestBodyParam bodyParam) throws IOException {
        return execute(this.domain,api,urlParam,bodyParam);
    }

    @Override
    public <T> T execute(String domain, Api api, ApiRequest.RequestUrlParam urlParam, ApiRequest.RequestBodyParam bodyParam) throws IOException {
        HttpRequestBase httpRequest = httpRequestBase(api, urlParam, bodyParam, domain);
        configHttpProxy(httpRequest);
        //noinspection unchecked
        return doExecute(httpRequest, (Class<T>)api.getResponseClass(),api.getResponseContentType());
    }

    @Override
    public <T> T execute(Api api, ApiRequest.RequestUrlParam urlParam, ApiRequest.RequestBodyParam bodyParam, Class<T> responseClass) throws IOException {
        HttpRequestBase httpRequest = httpRequestBase(api, urlParam, bodyParam, domain);
        configHttpProxy(httpRequest);
        return doExecute(httpRequest,responseClass,api.getResponseContentType());
    }

    @Override
    public <T> T execute(Api api, Map<String,Object> urlParam, ApiRequest.RequestBodyParam bodyParam, Class<T> responseClass) throws IOException{
        HttpRequestBase httpRequest = httpRequest(api,domain,urlParam,bodyParam);
        configHttpProxy(httpRequest);
        return doExecute(httpRequest,responseClass,api.getResponseContentType());
    }

    @Override
    public <T> T execute(Api api, Map<String,Object> urlParam, ApiRequest.RequestBodyParam bodyParam) throws IOException{
        HttpRequestBase httpRequest =httpRequest(api,domain,urlParam,bodyParam);
        configHttpProxy(httpRequest);
        //noinspection unchecked
        return doExecute(httpRequest,(Class<T>)api.getResponseClass(),api.getResponseContentType());
    }

    private HttpRequestBase httpRequestBase(Api api, ApiRequest.RequestUrlParam urlParam, ApiRequest.RequestBodyParam bodyParam, String domain) {
        Args.notBlank(domain, "API domain");
        HttpRequestBase httpRequest = httpRequest(api, domain, urlParam, bodyParam);
        configHttpProxy(httpRequest);
        return httpRequest;
    }

    private void configHttpProxy(HttpRequestBase requestBase){
        if (Objects.nonNull(httpProxy)) {
            RequestConfig config = RequestConfig.custom().setProxy(httpProxy).build();
            requestBase.setConfig(config);
        }
    }

    /**
     * <h3>METHOD DESCRIPTION <i>[ NAME: doExecute ]</i></h3>
     * do execute the api
     * @param httpRequest {@link HttpRequestBase http request}
     * @param resultClass {@link Class result class}
     * @param responseContentType {@link ContentType response content type}
     * @return {@link T response}
     * @throws IOException io exception
     * @author Asial Jim &nbsp;&nbsp;<span>Email:asialjim@hotmail.com &nbsp;&nbsp; asialjim@qq.com</span>
     * @since 2021/3/1 16:46
     */
    protected abstract <T> T doExecute(HttpRequestBase httpRequest, Class<T> resultClass, ContentType responseContentType) throws IOException;

    /**
     * <h3>METHOD DESCRIPTION <i>[ NAME: httpRequest ]</i></h3>
     * create http request by api http method
     * @param api {@link Api api}
     * @param domain {@link String api domain}
     * @return {@link HttpRequestBase http request}
     * @author Asial Jim &nbsp;&nbsp;<span>Email:asialjim@hotmail.com &nbsp;&nbsp; asialjim@qq.com</span>
     * @since 2021/3/1 16:47
     */
    protected HttpRequestBase httpRequest(Api api, String domain, ApiRequest.RequestUrlParam urlParam, ApiRequest.RequestBodyParam bodyParam){
        HttpRequestBase httpRequest = api.getHttpMethod().createHttpRequest(domain + api.getUri(), urlParam, bodyParam);
        configHttpProxy(httpRequest);
        return httpRequest;
    }

    /**
     * <h3>METHOD DESCRIPTION <i>[ NAME: httpRequest ]</i></h3>
     * create http request by api http method
     * @param api {@link Api api}
     * @param domain {@link String api domain}
     * @return {@link HttpRequestBase http request}
     * @author Asial Jim &nbsp;&nbsp;<span>Email:asialjim@hotmail.com &nbsp;&nbsp; asialjim@qq.com</span>
     * @since 2021/3/1 16:47
     */
    protected HttpRequestBase httpRequest(Api api, String domain, Map<String,Object> urlParam, ApiRequest.RequestBodyParam bodyParam){
        HttpRequestBase httpRequest = api.getHttpMethod().createHttpRequest(domain + api.getUri(), urlParam, bodyParam);
        configHttpProxy(httpRequest);
        return httpRequest;
    }
}